/*
 * 插件开发文档：https://ice.alibaba-inc.com/docs/plugin/develop/build
 */

'use stricts';

const fs = require('fs');
const path = require('path');
const themeVars = require('@txdfe/at-theme/apsara/js/index.js');

const cssvarWhiteList = Object.keys(themeVars).filter(
  (k) => k.toLowerCase() === k || /^S\d{1,2}$/.test(k),
);

// scss变量对象转为字符串
const getScssString = (scssMap = {}) => {
  const keys = Object.keys(scssMap);
  if (keys && keys.length) {
    return keys.reduce((prev, cur) => {
      return `${prev}$${cur}: ${scssMap[cur]};\n`;
    }, '');
  }
  return '';
};

const CSS_MODULE_REGEX = /\.module\.s?css\.d\.ts/;

module.exports = ({ context, onGetWebpackConfig, log }, userOptions) => {
  // 第一项参数为插件 API 提供的能力，第二项 userOptions 为插件自定义参数
  onGetWebpackConfig((config) => {
    let { theme = 'teambition' } = userOptions;
    const { commonSassResources, modifyVars, teamixPrefix } = userOptions;
    const isTs = fs.existsSync(path.join(context.rootDir, 'tsconfig.json'));
    ['css', 'css-module', 'scss', 'scss-module'].forEach((style) => {
      const rule = config.module.rule(style);
      // 为ts类型业务的css module生成类型定义文件
      if (isTs && (style === 'css-module' || style === 'scss-module')) {
        rule
          .use('typings-for-css-modules-loader')
          .loader(require.resolve('@teamsupercell/typings-for-css-modules-loader'))
          .before('css-loader');
      }
    });
    const availableTheme = ['teambition', 'apsara', 'infra'];
    if (!availableTheme.includes(theme)) {
      log.warn(
        '',
        '指定的主题不为 "teambition",  "apsara", "infra" 其中之一，已使用默认"teambition"主题',
      );
      theme = 'teambition';
    }
    let normalModifyVarsStr = '';
    let darkModifyVarsStr = '';
    if (modifyVars) {
      let hasNormal = false;
      let hasDark = false;
      if (
        modifyVars.normal &&
        Object.prototype.toString.call(modifyVars.normal) === '[object Object]'
      ) {
        hasNormal = true;
        normalModifyVarsStr = getScssString(modifyVars.normal);
      }
      if (
        modifyVars.dark &&
        Object.prototype.toString.call(modifyVars.dark) === '[object Object]'
      ) {
        hasDark = true;
        darkModifyVarsStr = getScssString(modifyVars.dark);
      }
      if (!hasNormal && !hasDark) {
        normalModifyVarsStr = getScssString(modifyVars);
        darkModifyVarsStr = getScssString(modifyVars);
      }
    }

    // 为了区别 at 和 teamix/ui，用 $teamix-prefix 作为hack teamix/ui基础组件样式的 prefix
    const teamixPrefixVarsStr = teamixPrefix ? `$teamix-prefix: '${teamixPrefix}';` : '';

    let prependData = `@import "~@txdfe/at-theme/${theme}/scss/index.scss";\n${normalModifyVarsStr}\n${teamixPrefixVarsStr}`;
    if (context.commandArgs.dark) {
      prependData = `@import "~@txdfe/at-theme/${theme}-dark/scss/index.scss";\n${darkModifyVarsStr}\n${teamixPrefixVarsStr}`;
    }

    // 注入主题变量
    ['scss', 'scss-module'].forEach((style) => {
      const rule = config.module.rule(style);
      rule
        .use('sass-loader')
        .loader(require.resolve('@txdfe/sass-loader')) // sass-loader换用@txdfe/sass-loader
        .tap((options) => {
          return {
            ...options,
            sourceMap: true, // resolve-url-loader要求sass-loader此配置项必须为true
            prependData,
            cssvar: {
              whiteList: cssvarWhiteList,
            },
          };
        });
      rule
        .use('resolve-url-loader')
        .loader(require.resolve('resolve-url-loader'))
        .options({
          keepQuery: true,
          removeCR: true,
        })
        .before('sass-loader');
      if (commonSassResources) {
        rule
          .use('sass-resources-loader')
          .loader(require.resolve('sass-resources-loader'))
          .options({
            resources: commonSassResources,
          })
          .after('sass-loader');
      }
    });

    // 删除其他插件对于url-loader的配置，重新定义
    ['woff2', 'ttf', 'eot', 'svg', 'img'].forEach((type) => {
      config.module.rules.delete(type);
    });
    config.module
      .rule('url-loader')
      .test(
        /\.(bmp|png|jpg|jpeg|gif|woff|woff2|eot|ttf|otf|svg|mp4|webm|wav|mp3|m4a|aac|oga)((\?|#).*)?$/,
      )
      .use('url-loader')
      .loader(require.resolve('url-loader'))
      .options({
        limit: 8192,
        name: 'assets/[hash].[ext]',
      });

    // 忽略css module 生成的.d.ts文件
    config.module.rule('tsx').exclude.add(CSS_MODULE_REGEX);

    config.module
      .rule('ignore')
      .test(CSS_MODULE_REGEX)
      .use('ignore-loader')
      .loader(require.resolve('ignore-loader'));

    // 设置css 打包在一个文件中
    config.plugin('MiniCssExtractPlugin').tap(([args]) => [
      {
        ...args,
        ignoreOrder: true, // 移除顺序警告
      },
    ]);

    config.optimization.splitChunks({
      // 控制分包数量
      minSize: 300000, // 覆盖webpack默认最小分包大小（30000）
      maxInitialRequests: 2, // 入口文件最大并行请求数
      maxAsyncRequests: 3, // 异步文件最大并行请求数

      // 覆盖ice默认配置，多entry也不打包vendor了
      // cacheGroups: {
      // vendor: {
      //   test: /[\\/]node_modules[\\/]/,
      //   name: 'vendor',
      //   chunks: 'initial',
      //   minChunks: 2,
      // },
      // },
    });

    // start命令指定devPublicPath，覆盖build.json中配置
    if (context.command === 'start' && context.commandArgs.devPublicPath) {
      const { devPublicPath } = context.commandArgs;
      config.output.publicPath(devPublicPath);
    }
  });
};
